﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using MusicApi.Service;
using MusicApi.Models;
using System.IO;
using System.Web;
using System.Net;
using System.Net.Http.Headers;
using System.Json;
using System.Runtime.Serialization.Json;
using Newtonsoft.Json;



namespace MusicApi.Controllers
{
    public class SongController : ApiController
    {
		ISongService _service;

        

		/* default constructor that sets the default used service */
		public SongController()
		{
			_service = new SongService();
			//_service = new SongServiceStub(); /* for testing */
		}

		/* Constructor for using injected service locator 
		 * e.g. for unit tests */
		public SongController(ISongService service)
		{
			_service = service;
		}
		
        // GET /api/song
        public IEnumerable<Song> Get()
        {
			var songs = _service.GetAllSongs();
			return songs;
        }

		
		
        // GET /api/song/asong.mp3
		public HttpResponseMessage Get([FromUri]string filename)
		{
			if (String.IsNullOrEmpty(filename.Trim()))
				throw new HttpResponseException("Error: missing filename parameter, e.g. /api/song/test.mp3", HttpStatusCode.PreconditionFailed);

			String path = String.Format(@"C:\tmp\{0}", filename.Trim());

			if (!File.Exists(path))
			{
				throw new HttpResponseException("Error: The file does not exist.", HttpStatusCode.NotFound);
			}
			try
			{
				MemoryStream responseStream = new MemoryStream();
				Stream fileStream = File.Open(path, FileMode.Open);
				bool fullContent = true;
				if (this.Request.Headers.Range != null)
				{
					fullContent = false;

					// Currently we only support a single range.
					RangeItemHeaderValue range = this.Request.Headers.Range.Ranges.First();


					// From specified, so seek to the requested position.
					if (range.From != null)
					{
						fileStream.Seek(range.From.Value, SeekOrigin.Begin);

						// In this case, actually the complete file will be returned.
						if (range.From == 0 && (range.To == null || range.To >= fileStream.Length))
						{
							fileStream.CopyTo(responseStream);
							fullContent = true;
						}
					}
					if (range.To != null)
					{
						// 10-20, return the range.
						if (range.From != null)
						{
							long? rangeLength = range.To - range.From;
							int length = (int)Math.Min(rangeLength.Value, fileStream.Length - range.From.Value);
							byte[] buffer = new byte[length];
							fileStream.Read(buffer, 0, length);
							responseStream.Write(buffer, 0, length);
						}
						// -20, return the bytes from beginning to the specified value.
						else
						{
							int length = (int)Math.Min(range.To.Value, fileStream.Length);
							byte[] buffer = new byte[length];
							fileStream.Read(buffer, 0, length);
							responseStream.Write(buffer, 0, length);
						}
					}
					// No Range.To
					else
					{
						// 10-, return from the specified value to the end of file.
						if (range.From != null)
						{
							if (range.From < fileStream.Length)
							{
								int length = (int)(fileStream.Length - range.From.Value);
								byte[] buffer = new byte[length];
								fileStream.Read(buffer, 0, length);
								responseStream.Write(buffer, 0, length);
							}
						}
					}
				}
				// No Range header. Return the complete file.
				else
				{
					fileStream.CopyTo(responseStream);
				}
				fileStream.Close();
				responseStream.Position = 0;

				HttpResponseMessage response = new HttpResponseMessage();
				response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent;
				response.Content = new StreamContent(responseStream);
				response.Content.Headers.ContentType = new MediaTypeHeaderValue("audio/mpeg3"); // set the mp3 content type in the response header 
				response.Content.Headers.Add("content-disposition", String.Format("attachment;filename={0}", filename));
				return response;
			}
			catch (IOException)
			{
				throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
			}
		}


		// POST /api/song/
        public HttpResponseMessage Post([FromUri]Song filename)
       {
		   String uploadDir = @"c:\tmp\uploads\";
           // Verify that this is an HTML Form file upload request
           var contype = Request.Content.GetType();
           if (!Request.Content.IsMimeMultipartContent("form-data"))
           {
               throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
           }
    
           // Create a stream provider for setting up output streams that saves the output under c:\tmp\uploads
           // If you want full control over how the stream is saved then derive from MultipartFormDataStreamProvider
           // and override what you need.
		   MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider( uploadDir );
   
           // Read the MIME multipart content using the stream provider we just created.
           var bodyparts = Request.Content.ReadAsMultipartAsync(streamProvider);
		   bodyparts.Wait();

		   /* method in the service that renames the files to a guid and moves the into mp3 dir */
		   _service.HandleUploadFiles( uploadDir );

		   // Get a dictionary of local file names from stream provider.
           // The filename parameters provided in Content-Disposition header fields are the keys.
           // The local file names where the files are stored are the values.
           IDictionary<string, string> bodyPartFileNames = streamProvider.BodyPartFileNames;
    
           // Create response containing information about the stored files.

		   return new HttpResponseMessage(HttpStatusCode.Accepted); 
       }

       public HttpResponseMessage Put([FromUri]Song filename) 
       {
		   try
		   {
			   var content = Request.Content;
			   String songString = HttpUtility.UrlDecode(content.ReadAsStringAsync().Result);
			   var count = songString.Count(x => x == '&') + 1;
			   Song song = new Song();
			   //int count = Regex.Matches(ncont, "&").Count;


			   //var count = 6;
			   var split = songString.Split('&').ToArray();

			   if (count > 0)
			   {
				   if (split[0].Contains("title="))
				   {
					   var a = split[0];
					   var b = a.Substring(6);
					   song.title = b;
				   }
			   }

			   if (count > 1)
			   {
				   if (split[1].Contains("songId="))
				   {
					   var a = split[1];
					   var b = a.Substring(7);
					   song.songId = b;
				   }
			   }

			   if (count > 2)
			   {
				   if (split[2].Contains("filename="))
				   {
					   var a = split[2];
					   var b = a.Substring(9);
					   song.filename = b;
				   }
			   }

			   if (count > 3)
			   {
				   if (split[3].Contains("guitarPartyId"))
				   {
					   var a = split[3];
					   var b = a.Substring(14);
					   song.guitarPartyId = b;
				   }
			   }

			   if (count > 4)
			   {
				   if (split[4].Contains("artist="))
				   {
					   var a = split[4];
					   var b = a.Substring(7);
					   song.artist = b;
				   }
			   }

			   if (count > 5)
			   {
				   if (split[5].Contains("album="))
				   {
					   var a = split[5];
					   var b = a.Substring(6);
					   song.album = b;
				   }
			   }

			   if (count > 6)
			   {
				   if (split[6].Contains("genre="))
				   {
					   var a = split[6];
					   var b = a.Substring(6);
					   song.genre = b;
				   }
			   }
			   _service.HandleUpdateID3(song);
			   return new HttpResponseMessage(HttpStatusCode.OK);
		   }
		   catch(Exception ex)
		   {
			   throw new HttpResponseException(HttpStatusCode.PreconditionFailed);
		   }
       }

        // DELETE /api/song/5
        public void Delete(int id)
        {
        }
    }
}
